package com.tavio.vaultboy.element;

import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;

import com.tavio.vaultboy.element.state.GravityState;
import com.tavio.vaultboy.element.type.ElementType;
import com.tavio.vaultboy.scene.SceneManager;
import com.tavio.vaultboy.util.vector.Vector;


public class Box extends TouchableSpriteElement {
	
	public int pushMovement;
	
	private Element collidedY = null;
	
	private Element collidedX = null;
	
	private float oldPlayerX;
	
	public Box(float x, float y, float width, float height,
			float acceleration, ITextureRegion tiledTextureRegion, VertexBufferObjectManager vertexBufferObjectManager) {
		super(ElementType.BOX, x, y, width, height, acceleration, tiledTextureRegion, vertexBufferObjectManager);
		pushMovement = 0;
	}

	@Override
	public void updatePositionAndCheckCollisions(float timeElapsed) {
		velocityY += acceleration * accelerationModifier * timeElapsed;
		if(velocityY > 10)
			velocityY = 10;
		y += velocityY;
		getBoundingBox().update();
		
		for(Element element : SceneManager.getInstance().collidableElements) {
			if(getBoundingBox().collidesWith(element.getBoundingBox()) && 
					! this.equals(element)) {
				collidedY = element;
				// Move back the object
				y -= velocityY;
				getBoundingBox().update();
				velocityY = 0;	
				
				// Now move it again so it touches the element it would have collided with  
				
				if(GravityState.DOWN.equals(SceneManager.getInstance().gravityState)) {
					if(collidedY.getBoundingBox().top >= getBoundingBox().bottom) {
						y = collidedY.getBoundingBox().top - getSprite().getHeight();
					}
					else 
						y = collidedY.getBoundingBox().bottom;
					
				} else {
					if(collidedY.getBoundingBox().bottom <= getBoundingBox().top) {
						y = collidedY.getBoundingBox().bottom;
						
					}
					else
						y = collidedY.getBoundingBox().top - getSprite().getHeight();
				}
				break;
				
			}
		}
		
		if(collidedY == null)
			pushMovement = 0;
		
		velocityX = pushMovement * 7.5f; //Push movement != 0 if box is being pushed
		
		x += velocityX;
		getBoundingBox().update();
		
		for(Element element : SceneManager.getInstance().collidableElements) {
			if(getBoundingBox().collidesWith(element.getBoundingBox()) && 
					! this.equals(element)) {
				collidedX = element;	
				// Move back the object
				x -= velocityX;
				getBoundingBox().update();
				velocityX = 0;	
				
				// Now move it again so it touches the element it would have collided with
				
				if(collidedX.getBoundingBox().left >= getBoundingBox().right)  //Element is on the right
					x = collidedX.getBoundingBox().left - getSprite().getWidth();
				else 
					x = collidedX.getBoundingBox().right;
					
				break;
			}
		}
		
		getSprite().setPosition(x, y);
		getBoundingBox().update();
		
		/* If the box is being pushed, the player must be brought close to it. If not, there will be a gap between the
		 * box and the player. This happens because the player moves towards the box first and its collision detection
		 * with the box moves him back. Then, it's the box's turn to move forward, thus creating the gap.
		 * After repositioning the player, we must check for collisions with him and the other objects in the scene. If
		 * the player in its new position collides on the x axis, we move him back, make him drop the box and move back
		 * the box.
		 */
		
		oldPlayerX = SceneManager.getInstance().getVaultBoy().x;
		
		if(pushMovement > 0 && SceneManager.getInstance().getVaultBoy().getBoundingBox().right <= getBoundingBox().left) {
			// Box is being pushed from the left
			SceneManager.getInstance().getVaultBoy().x = getBoundingBox().left - SceneManager.getInstance().getVaultBoy().getSprite().getWidth();
			SceneManager.getInstance().getVaultBoy().getBoundingBox().update();
			
			for(Element element : SceneManager.getInstance().collidableElements) {
				if(SceneManager.getInstance().getVaultBoy().getBoundingBox().collidesWith(element.getBoundingBox()) && 
						! ElementType.VAULT_BOY.equals(element.elementType)) {
					SceneManager.getInstance().getVaultBoy().x = oldPlayerX;
					this.pushMovement = 0;
					this.x -= velocityX;
					velocityX = 0;
					SceneManager.getInstance().getVaultBoy().boxBeingGrabbed = null;
					break;
				}
			}
			
			getBoundingBox().update();
			getSprite().setPosition(x, y);
			
			SceneManager.getInstance().getVaultBoy().getBoundingBox().update();
			
			SceneManager.getInstance().getVaultBoy().getSprite().setPosition(SceneManager.getInstance().getVaultBoy().x, SceneManager.getInstance().getVaultBoy().y);
			
		}
		else if (pushMovement < 0 && SceneManager.getInstance().getVaultBoy().getBoundingBox().left >= getBoundingBox().right) {
			// Box is being pushed from the right
			SceneManager.getInstance().getVaultBoy().x = getBoundingBox().right;
			SceneManager.getInstance().getVaultBoy().getBoundingBox().update();
			
			for(Element element : SceneManager.getInstance().collidableElements) {
				if(SceneManager.getInstance().getVaultBoy().getBoundingBox().collidesWith(element.getBoundingBox()) && 
						! ElementType.VAULT_BOY.equals(element.elementType)) {
					SceneManager.getInstance().getVaultBoy().x = oldPlayerX;
					this.pushMovement = 0;
					this.x -= velocityX;
					velocityX = 0;
					SceneManager.getInstance().getVaultBoy().boxBeingGrabbed = null;
					break;
				}
			}
			
			getBoundingBox().update();
			getSprite().setPosition(x, y);
			
			SceneManager.getInstance().getVaultBoy().getBoundingBox().update();
			
			SceneManager.getInstance().getVaultBoy().getSprite().setPosition(SceneManager.getInstance().getVaultBoy().x, SceneManager.getInstance().getVaultBoy().y);
			
		}
		
		collidedY = null;
		collidedX = null;
	}

	@Override
	public void onTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX,
			float pTouchAreaLocalY) {
		
		float bulletX, bulletY;
		
		bulletX = SceneManager.getInstance().getVaultBoy().x + SceneManager.getInstance().getVaultBoy().width /2;
		bulletY = SceneManager.getInstance().getVaultBoy().y + SceneManager.getInstance().getVaultBoy().height / 2;
		
		if(SceneManager.getInstance().bullet == null && pSceneTouchEvent.isActionUp()) {
			Vector direction, bulletPos, boxPos;
			
			boxPos = new Vector(x + width/2, y + height/2);
			bulletPos = new Vector(bulletX, bulletY);
			direction = boxPos.subtract(bulletPos).normalize();
			
			SceneManager.getInstance().addBulletToScene(new Bullet(bulletX, bulletY, direction, vertexBufferObjectManager));
		}
		
	}
}
